﻿using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SmartPowerHub.Communication.Modbus
{
    public class ModbusTcpHelper
    {
        private EndianFormat _endianFormat;

        private StringFormat _stringFormat;

        public ModbusTcpHelper(EndianFormat endianFormat, StringFormat stringFormat)
        {
            _endianFormat = endianFormat;
            _stringFormat = stringFormat;
        }

        /// <summary>
        /// 生成一个事务Id
        /// </summary>
        public ushort SetNextTransactionId()
        {
            int transactionId = 0;
            return (ushort)Interlocked.Increment(ref transactionId);
        }

        /// <summary>
        /// 组装写入数据请求报文
        /// </summary>
        /// <param name="functionCode"></param>
        /// <param name="startAddress"></param>
        /// <param name="values"></param>
        /// <param name="unitId"></param>
        /// <returns></returns>
        public byte[] BuildWriteRequest<T>(FunctionCode functionCode, ushort startAddress, byte[] dataBuffer, ushort transactionId, byte unitId)
        {
            List<byte> frame = new List<byte>();
            frame.Add(BitConverter.GetBytes(transactionId)[1]);// 事务ID
            frame.Add(BitConverter.GetBytes(transactionId)[0]);
            frame.Add(0x0);  // 协议标识符高字节(0)
            frame.Add(0x0); // 协议标识符低字节(0)

            if (dataBuffer.Length > 2)
            {
                // 计算报文长度
                ushort byteCount = (ushort)dataBuffer.Length;
                ushort count = (ushort)(byteCount / 2);

                int length = 1 + 1 + 2 + 2 + 1 + byteCount;//单元 ID + PDU长度

                frame.Add(BitConverter.GetBytes(length)[1]);  // 长度
                frame.Add(BitConverter.GetBytes(length)[0]);
                frame.Add(unitId);  // 单元标识符（1字节）

                frame.Add((byte)functionCode);  // 功能码（1字节）
                frame.Add(BitConverter.GetBytes(startAddress)[1]);  // 起始地址
                frame.Add(BitConverter.GetBytes(startAddress)[0]);

                frame.Add(BitConverter.GetBytes(count)[1]);      // 寄存器数量
                frame.Add(BitConverter.GetBytes(count)[0]);

                frame.Add((byte)byteCount);  // 字节计数（1字节）
            }
            else
            {
                int length = 4 + dataBuffer.Length; // 基本长度
                frame.Add(BitConverter.GetBytes((ushort)length)[1]);// 长度
                frame.Add(BitConverter.GetBytes((ushort)length)[0]);

                frame.Add(unitId); // 单元标识符
                frame.Add((byte)functionCode); // 功能码
                frame.Add(BitConverter.GetBytes(startAddress)[1]);// 起始地址
                frame.Add(BitConverter.GetBytes(startAddress)[0]);
            }

            // 数据部分
            frame.AddRange(dataBuffer);
            return frame.ToArray();
        }

        /// <summary>
        /// 组装读取数据请求报文
        /// </summary>
        /// <returns></returns>
        public byte[] BuildReadRequest(FunctionCode functionCode, ushort startAddress, ushort count, ushort transactionId, byte unitId)
        {
            List<byte> message = new List<byte>();

            message.Add(BitConverter.GetBytes(transactionId)[1]);  // 事务ID（2字节，大端）
            message.Add(BitConverter.GetBytes(transactionId)[0]);
            message.Add(0x0);  // 协议标识符高字节(0)
            message.Add(0x0); // 协议标识符低字节(0)

            int length = 6;//长度=单元ID + PDU 

            message.Add(BitConverter.GetBytes((ushort)length)[1]);// 长度
            message.Add(BitConverter.GetBytes((ushort)length)[0]);
            message.Add(unitId); // 单元标识符
            message.Add((byte)functionCode); // 功能码
            message.Add(BitConverter.GetBytes(startAddress)[1]);// 起始地址
            message.Add(BitConverter.GetBytes(startAddress)[0]);

            message.Add(BitConverter.GetBytes(count)[1]);// 数量
            message.Add(BitConverter.GetBytes(count)[0]);
            return message.ToArray();
        }

        /// <summary>
        /// 解析读取数据返回的报文
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataBuffer"></param>
        /// <param name="functionCode"></param>
        /// <param name="count"></param>
        /// <param name="transactionId"></param>
        /// <returns></returns>
        public async Task<ModbusResponse<T>> ReadResponse<T>(byte[] dataBuffer, FunctionCode functionCode, ushort count, ushort transactionId)
        {
            ModbusResponse<T> modbusResponse = new ModbusResponse<T>();
            try
            {
                //验证事务Id
                ushort transactionIdValue = BinaryPrimitives.ReadUInt16BigEndian(dataBuffer.AsSpan(0, 2));
                if (transactionId != BinaryPrimitives.ReadUInt16BigEndian(dataBuffer.AsSpan(0, 2)))
                {
                    modbusResponse.State = false;
                    modbusResponse.Message = $"事务标识符{transactionIdValue}与{transactionId}不匹配";
                    return modbusResponse;
                }
                //验证长度
                ushort length = BinaryPrimitives.ReadUInt16BigEndian(dataBuffer.AsSpan(4, 2));

                //验证功能码
                if ((dataBuffer[7] & 0x80) != 0)
                {
                    byte exceptionCode = dataBuffer[8];
                    modbusResponse.State = false;
                    modbusResponse.Message = $"Modbus TCP异常响应: 功能码 {dataBuffer[7] & 0x7F}, 异常码 {exceptionCode}";
                    return modbusResponse;
                }
                //提取数据部分
                byte[] data = dataBuffer.ToList().GetRange(9, dataBuffer[8]).ToArray();
                modbusResponse.Buffer = data.ByteFormat(_endianFormat);
                if (typeof(T) != typeof(string))
                {
                    modbusResponse.ValueArray = ByteHelper.GetResult<T>(data, _endianFormat);
                    int typeLength = Marshal.SizeOf(typeof(T));
                    if (typeLength == (count * 2))
                    {
                        modbusResponse.Value = modbusResponse.ValueArray[0];
                    }
                }
                else
                {
                    if (_stringFormat == StringFormat.ASCII)
                    {
                        modbusResponse.ValueArray = new T[] { (T)(object)Encoding.ASCII.GetString(modbusResponse.Buffer, 0, modbusResponse.Buffer.Length) };
                    }
                    else
                    {
                        modbusResponse.ValueArray = new T[] { (T)(object)Encoding.ASCII.GetString(modbusResponse.Buffer, 0, modbusResponse.Buffer.Length) };
                    }
                    modbusResponse.Value = modbusResponse.ValueArray[0];
                }

                return modbusResponse;
            }
            catch (Exception ex)
            {
                modbusResponse.State = false;
                modbusResponse.Message = ex.Message;
            }
            return modbusResponse;
        }

        /// <summary>
        /// 验证写入数据返回的报文
        /// </summary>
        /// <param name="response">设备返回的字节数组</param>
        /// <param name="startAddress">输出参数：起始地址</param>
        /// <param name="quantity">输出参数：写入的寄存器数量</param>
        /// <returns>是否解析成功</returns>
        public  async Task<ModbusResponse> ValidateWriteResponse(byte[] dataBuffer, FunctionCode functionCode, ushort startAddress, byte slaveAddress = 0x01)
        {
            ModbusResponse modbusResponse = new ModbusResponse();
            try
            {
                ushort transactionId = BinaryPrimitives.ReadUInt16BigEndian(dataBuffer.AsSpan(0, 2));
                // 验证响应长度是否正确（MBAP头7字节 + PDU 5字节 = 12字节）
                if (dataBuffer == null || dataBuffer.Length != 12)
                {
                    modbusResponse.State = false;
                    modbusResponse.Message = $"数据长度不符合";
                    return modbusResponse;
                }
                // 验证功能码（第7字节是功能码）
                if (dataBuffer[7] != (byte)functionCode)
                {
                    modbusResponse.State = false;
                    modbusResponse.Message = $"{dataBuffer[7]}，功能码不匹配";
                    return modbusResponse;
                }

                // 解析起始地址（第8-9字节）
                if (startAddress != BitConverter.ToUInt16(new byte[] { dataBuffer[9], dataBuffer[8] }, 0))
                {
                    modbusResponse.State = false;
                    modbusResponse.Message = $"响应地址不匹配，预期{startAddress}，实际{BitConverter.ToUInt16(new byte[] { dataBuffer[9], dataBuffer[8] }, 0)}";
                    return modbusResponse;
                }
                //// 解析写入的寄存器数量（第10-11字节）
                //if (typeLength != BitConverter.ToUInt16(new byte[] { response[11], response[10] }, 0))
                //{
                //    modbusResponse.State = false;
                //    modbusResponse.Message = $"响应数据数量不匹配，预期{typeLength}，实际{BitConverter.ToUInt16(new byte[] { response[11], response[10] }, 0)}";
                //    return modbusResponse;
                //}
            }
            catch (Exception ex)
            {
                modbusResponse.State = false;
                modbusResponse.Message = ex.Message;
            }
            return modbusResponse;
        }

    }
}
